package com.adv.ems.service.impl;

import cn.hutool.json.JSONUtil;
import com.adv.ems.db.entity.*;
import com.adv.ems.manager.*;
import com.adv.ems.model.dto.BusinessException;
import com.adv.ems.model.dto.UserSubjectInfo;
import com.adv.ems.model.param.LoginParam;
import com.adv.ems.model.vo.LoginVO;
import com.adv.ems.service.UserLoginService;
import com.adv.ems.utils.JwtUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserLoginServiceImpl extends BaseServiceImpl implements UserLoginService {
    @Resource
    UserManager userManager;
    @Resource
    InstituteInfoManager instituteInfoManager;
    @Resource
    BuildingInfoManager buildingInfoManager;
    @Resource
    DepartmentInfoManager departmentInfoManager;
    @Resource
    SystemMenuManager systemMenuManager;

    @Override
    public LoginVO login(LoginParam content, String acceptLanguage) {
        UserDO user = userManager.getUserByUsername(content.getUsername());
        if (user == null || !content.getPassword().equals(user.getPassword())) {
            throw new BusinessException("账号或密码错误");
        }
        LoginVO login = new LoginVO();
        login.setNick(user.getNick());
        login.setToken(JwtUtil.createToken(user));

        String relateSubject = user.getRelateSubject();
        UserSubjectInfo userSubjectInfo;
        if (relateSubject == null) {
            userSubjectInfo = new UserSubjectInfo();
        }else {
            userSubjectInfo = JSONUtil.toBean(relateSubject, UserSubjectInfo.class);
        }
        Map<Long, BuildingInfoDO> buildingMap = buildingInfoManager.getAllMap();
        List<LoginVO.SubjectInfo> buildings = userSubjectInfo
                .getBuilding()
                .stream()
                .map(buildingMap::get)
                .filter(Objects::nonNull)
                .map(s -> LoginVO.SubjectInfo.build(s, getAllMeterIdsByBuilding(s.getId()).size(), acceptLanguage))
                .collect(Collectors.toList());
        login.setBuildings(buildings);

        Map<Long, InstituteInfoDO> instituteMap = instituteInfoManager.getAllMap();
        List<LoginVO.SubjectInfo> institutes = userSubjectInfo
                .getInstitute()
                .stream()
                .map(instituteMap::get)
                .filter(Objects::nonNull)
                .map(s -> LoginVO.SubjectInfo.build(s, getBuildingIdsByInstitution(s.getId()).size(), getAllMeterIdsByInstitution(s.getId()).size(), acceptLanguage))
                .collect(Collectors.toList());
        login.setInstitutes(institutes);

        Map<Long, DepartmentInfoDO> departmentMap = departmentInfoManager.getAllMap();
        List<LoginVO.SubjectInfo> departments = userSubjectInfo
                .getDepartment()
                .stream()
                .map(departmentMap::get)
                .filter(Objects::nonNull)
                .map(s -> LoginVO.SubjectInfo.build(s, getMeterIdsByDepartment(s.getId()).size(), acceptLanguage))
                .collect(Collectors.toList());
        login.setDepartments(departments);
        getMenus(login.getMenus(), null, null);
        return login;
    }


    private void getMenus(List<LoginVO.Menu> parents, Set<Long> existedIds, Map<Long, List<LoginVO.Menu>> parentIdToChildren) {
        if (parents.isEmpty()) {
            List<SystemMenuDO> list = systemMenuManager
                    .getAllMap()
                    .values()
                    .stream()
                    .filter(m -> m.getEnable() > 0)
                    .sorted(Comparator.comparing(SystemMenuDO::getSort))
                    .collect(Collectors.toList());
            Map<Long, List<LoginVO.Menu>> map = list
                    .stream()
                    .filter(m -> m.getParentId() != null)
                    .map(LoginVO.Menu::new)
                    .collect(Collectors.groupingBy(LoginVO.Menu::getParentId));
            List<LoginVO.Menu> roots = list
                    .stream()
                    .filter(m -> m.getParentId() == null)
                    .map(LoginVO.Menu::new)
                    .collect(Collectors.toList());
            parents.addAll(roots);
            if (!CollectionUtils.isEmpty(roots)) {
                getMenus(roots, new HashSet<>(), map);
            }
        }else {
            for (LoginVO.Menu parent : parents) {
                if (existedIds.contains(parent.getId())) {
                    return;
                }
                existedIds.add(parent.getId());
                List<LoginVO.Menu> children = parentIdToChildren.getOrDefault(parent.getId(), new ArrayList<>());
                parent.setChildren(children);
                if (!CollectionUtils.isEmpty(children)) {
                    getMenus(children, existedIds, parentIdToChildren);
                }
            }

        }
    }
}
